iT邦幫忙

2025 iThome 鐵人賽

DAY 22
1

接下來要介紹的實例,是員工資料清單表格<EmployeeTable />,其中涉及到跨組件(component)的資料傳遞,即props(父傳子)及emits(子傳父),先參考以下程式碼:

<!-- src/views/Employee.vue -->
<template>
  <section id="member-settings">
    <h1>成員設定</h1>

    <!-- 員工資料清單表格 -->
    <EmployeeTable
      :employees="employees"
      @edit="openEdit"
      @delete="confirmDelete"
      :current-page="currentPage"
      :page-size="pageSize"
    />

  </section>
</template>

我們可以看到:employees=”employees”的語法,左邊的:employees,代表<EmployeeTable />元件的props名稱,右邊的”employees”,代表父組件的datacomputed變數,乃用於傳送資料給子組件。

至於@edit=”openEdit”的語法,左邊的@edit,代表emits名稱為edit的事件,而該事件乃來自於子組件,並受到父組件監聽,右邊的”openEdit”,代表父組件的方法,於接收子組件的事件與參數後,以此進行函式運算。

簡單彙總props及emits語法,參考如下:

<!-- 父組件把資料傳給子組件的props -->
:propName="父組件資料"

<!-- 子組件用$emit('eventName', payload)發事件給父組件 -->
@eventName="父組件方法"

至於若要確認父、子組件之間的資料傳遞與事件連結方式,要參考父組件區塊中props傳遞與emit事件的設定,即:

// src/views/Employee.vue
import store from "@/store";
import { mapGetters } from "vuex";

// 註冊EmployeeTable子組件,父組件透過props把資料傳給它,並監聽它的emits(事件)
import EmployeeTable from "@/components/Employee/EmployeeTable.vue";

export default {
  name: "EmployeePage",
  components: {

    EmployeeTable,

  },

  // 接收Vuex狀態(state/getters),部分資料以props傳遞給子組件EmployeeTable.vue
  computed: {
	// Vuex getters(唯讀)
    ...mapGetters("employee", [
    
      "pageSize",
      "employees",

    ]),
    
    // 採用getter/setter形式,同時也可支援雙向綁定,如v-model="currentPage"
    currentPage: {
	  // getter
      get() {
        return this.$store.state.employee.currentPage;
      },
      // setter
      set(newPage) {
        this.$store.commit(`employee/${SET_CURRENT_PAGE}`, newPage);
      }
    }
  },

  methods: {

	// 接收來自子組件EmployeeTable.vue的@edit事件(emits)
    openEdit(emp) {
      this.isEdit = true;
      this.editingEmployee = emp;
      this.showModal = true;
    },

	// 接收來自子組件EmployeeTable.vue的@delete事件(emits)
    confirmDelete(emp) {
      if (!confirm(`確定刪除 ${emp.name}?`)) return;
      
      this.$store.dispatch(`employee/${DELETE_EMPLOYEE}`, emp.id)
        .then(() => {
          this.refreshList();
        });
    },

  },

};
  • 首先匯入放置於src/components/Employee的子組件EmployeeTable.vue,並於父組件的components中註冊,以便於<template />中直接使用<EmployeeTable />元件。
  • <EmployeeTable />中共有三個props:
    • 其中employeespage-size,乃經Vuex getters讀取狀態後,藉由computed變數employeespageSize分別取得資料,再傳給子組件
    • current-page,則經由Vuex getter讀取狀態或setter更新狀態後,藉由computed變數currentPage取得資料後,再傳給子組件。
  • <EmployeeTable />中共有二個emits,則分別監聽來自子組件的editdelete事件,接收emp參數後,分別執行函式openEdit(emp)confirmDelete(emp),分別為開啟編輯模式modal及刪除員工資料。

進一步看子組件EmployeeTable.vue,如:

<!-- src/components/Employee/EmployeeTable.vue -->
<template>
  <b-table
    :items="items"
    :fields="fields"
  >

    <!-- 序號欄:顯示計算後的index -->
    <template #cell(index)="row">
      {{ row.item.index }}
    </template>

    <!-- 操作欄:三點選單 -->
    <template #cell(actions)="row">
      <b-dropdown right size="sm" variant="link" no-caret>
        <template #button-content>
          <i class="fas fa-ellipsis-v"></i>
        </template>
        <!-- 點擊後通知父組件,並傳回該列資料row.item -->
        <b-dropdown-item @click="$emit('edit', row.item)">編輯</b-dropdown-item>
        <b-dropdown-item @click="$emit('delete', row.item)">刪除</b-dropdown-item>
      </b-dropdown>
    </template>
    
  </b-table>
</template>
// src/components/Employee/EmployeeTable.vue
export default {
  name: "EmployeeTable",
  
  // 父組件透過props傳入資料(employees, currentPage, pageSize),供表格顯示與計算
  props: {
    employees: { type: Array, required: true },
    currentPage: { type: Number, required: true },
    pageSize: { type: Number, required: true }
  },
  
  // 回傳給父組件的事件(edit, delete),並傳回選取列的資料(row.item)
  emits: ["edit", "delete"],
  
  computed: {
  
    // 將父組件傳入的employees轉換成表格顯示用items,以顯示資料畫面
    items() {
      return this.employees.map((emp, idx) => ({
        ...emp,
        index: (this.currentPage - 1) * this.pageSize + idx + 1
      }));
    }
    
  }
};
  • 子組件有使用到BootstrapVue的元件<b-table />,相關的使用方式,可參考官方網站文件
    BootstrapVue Table,於此不再贅述。
  • 我們將焦點集中於子組件如何使用父組件透過props傳入的資料,即於computed屬性中,將employeescurrentPagepageSize進行運算,產成items(),並綁定至<b-table />:items屬性,以渲染表格內容並呈現員工資料。
  • 表格中,有設置三點選單的操作欄位,經點擊對應的按鈕,觸發事件(editdelete)後,再透過emit事件回傳該列資料row.item給父組件使用。

到此,我們總算完成跨組件props及emits的介紹,藉由區分各組件進行撰寫,可達到不同功能集中在對應組件內管理的作用,除了方便日後程式修改,也適於可解讀性,這一切都要歸功於父、子組件傳遞資料的強大功能。


上一篇
Day 21: Vue中進行API請求
系列文
從零打造網頁系統:非資訊人也能完成的全端專題實作22
圖片
  熱門推薦
圖片
{{ item.channelVendor }} | {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言